import os
import shutil
import zipfile
import unittest
import tempfile
import contextlib

import pluginlib.manager

class OnPluginFoundCallback(object):
    def __init__(self, test, plugins):
        self.test = test
        self.plugins = plugins

    def __call__(self, plugin_path, plugin_type):
        plug = (plugin_path, plugin_type)
        self.test.assert_(plug in self.plugins,
                          "Plugin found is invalid %s" % (plug,))
        self.plugins.remove(plug)

class  PluginFinderTest(unittest.TestCase):
    def __init__(self, *args, **kwargs):
        unittest.TestCase.__init__(self, *args, **kwargs)
        self.dir = None
        self.finder = None

    def setUp(self):
        self.dir = tempfile.mkdtemp(prefix='pluginlib-test')
        self.finder = pluginlib.manager.PluginFinder([self.dir])

    def tearDown(self):
        shutil.rmtree(self.dir)
        self.dir = None
        self.finder = None

    def create_dir_plugin(self, *path_components):
        dir_name = os.path.join(self.dir, *path_components)
        if not os.path.exists(dir_name):
            os.makedirs(dir_name)
        cfg_file = os.path.join(dir_name, 'plugin.conf')
        with open(cfg_file, 'w') as f:
            f.write('[Plugin]\n')
            f.write('name: test\n')
            f.write('version: 1.0\n')
            f.write('load modules: test\n')

    def create_zip_plugin(self, *path_components):
        dir_name = os.path.join(self.dir, *path_components[:-1])
        if len(path_components) > 1 and not os.path.exists(dir_name):
            os.makedirs(dir_name)
        zip_file_name = os.path.join(self.dir, *path_components)
        with contextlib.closing(zipfile.ZipFile(zip_file_name,
                                                'w')) as zip_file:
            with tempfile.NamedTemporaryFile(prefix='pluginlib-test') as f:
                f.write('[Plugin]\n')
                f.write('name: test\n')
                f.write('version: 1.0\n')
                f.write('load modules: test\n')
                f.flush()
                zip_file.write(f.name, 'plugin.conf')

    def test_find_dir_simple(self):
        self.create_dir_plugin('test')

        plugins = [(os.path.join(self.dir, 'test'), 'dir')]
        self.finder.find_plugins(OnPluginFoundCallback(self, plugins))

    def test_find_zip_simple(self):
        self.create_zip_plugin('test.zip')

        plugins = [(os.path.join(self.dir, 'test.zip'), 'zip')]
        self.finder.find_plugins(OnPluginFoundCallback(self, plugins))

    def test_find_zip_invalid(self):
        zip_file_name = os.path.join(self.dir, 'test.zip')
        with contextlib.closing(zipfile.ZipFile(zip_file_name, 'w')):
            pass

        plugins = []
        self.finder.find_plugins(OnPluginFoundCallback(self, plugins))

    def test_find_dir_in_subdir(self):
        self.create_dir_plugin('somedir', 'test')

        plugins = [(os.path.join(self.dir, 'somedir', 'test'), 'dir')]
        self.finder.find_plugins(OnPluginFoundCallback(self, plugins))

    def test_find_zip_in_subdir(self):
        self.create_zip_plugin('somedir', 'test.zip')

        plugins = [(os.path.join(self.dir, 'somedir', 'test.zip'), 'zip')]
        self.finder.find_plugins(OnPluginFoundCallback(self, plugins))

    def test_find_multiple(self):
        self.create_dir_plugin('test_dir')
        self.create_zip_plugin('test_zip.zip')
        self.create_dir_plugin('somedir', 'test_dir')
        self.create_zip_plugin('somedir', 'test_zip.zip')

        plugins = [(os.path.join(self.dir, 'test_dir'), 'dir'),
                   (os.path.join(self.dir, 'test_zip.zip'), 'zip'),
                   (os.path.join(self.dir, 'somedir', 'test_dir'), 'dir'),
                   (os.path.join(self.dir, 'somedir', 'test_zip.zip'), 'zip')]
        self.finder.find_plugins(OnPluginFoundCallback(self, plugins))

if __name__ == '__main__':
    unittest.main()

